import {Component, Input, OnInit} from '@angular/core';
import Map from 'ol/Map';
import {Raster as RasterSource} from 'ol/source';
import {UtilComponent} from '../../interface/util-component.interface';
import {NzMessageService} from 'ng-zorro-antd';
import ImageLayer from 'ol/layer/Image';
import Stamen from 'ol/source/Stamen';
import OSM from 'ol/source/OSM';

@Component({
    selector: 'kylin-color-manipulation',
    templateUrl: './color-manipulation.component.html',
    styleUrls: ['./color-manipulation.component.less']
})
export class ColorManipulationComponent implements OnInit, UtilComponent {
    hue = 0;
    chroma = 50;
    lightness = 50;

    raster: RasterSource;
    imageLayer: any;

    hasContent = false;
    map: Map;
    isSupport: boolean;
     Xn = 0.950470;
     Yn = 1;
     Zn = 1.088830;
     t0 = 4 / 29;
     t1 = 6 / 29;
     t2 = 3 * this.t1 * this.t1;
     t3 = this.t1 * this.t1 * this.t1;
     twoPi = 2 * Math.PI;
    @Input() set data(val) {
        Object.assign(this, val);
    };

    constructor(private message: NzMessageService) {
    }

    ngOnInit() {
        this.start()
    }

    start() {
        /*const stamenSource = new RasterSource({
            sources: [new Stamen({
                layer: 'watercolor',
                transition: 0
            } as any)]
        });*/
        const stamenSource = new RasterSource({
            sources: [new OSM()]
        });
        const imageLayer = new ImageLayer({
            source: stamenSource
        });
        this.imageLayer = imageLayer;
        this.map.addLayer(this.imageLayer);
        // 获取最上层图层 source
        // const mapSource = (this.map.getLayers().item(this.map.getLayers().getLength() - 1) as any ).getSource();
        const mapSource = stamenSource;
        if (mapSource instanceof RasterSource) { // TODO 如何判断是否为栅格数据源
            this.raster = mapSource;
            this.isSupport = true;
            this.raster.setOperation((pixels, data: any) => {
                const hcl = this.rgb2hcl(pixels[0]);

                let h = hcl[0] + Math.PI * data.hue / 180;
                if (h < 0) {
                    h += this.twoPi;
                } else if (h > this.twoPi) {
                    h -= this.twoPi;
                }
                hcl[0] = h;

                hcl[1] *= (data.chroma / 100);
                hcl[2] *= (data.lightness / 100);

                return this.hcl2rgb(hcl);
            }, {
                rgb2hcl: this.rgb2hcl,
                hcl2rgb: this.hcl2rgb,
                rgb2xyz: this.rgb2xyz,
                lab2xyz: this.lab2xyz,
                xyz2lab: this.xyz2lab,
                xyz2rgb: this.xyz2rgb,
                Xn: this.Xn,
                Yn: this.Yn,
                Zn: this.Zn,
                t0: this.t0,
                t1: this.t1,
                t2: this.t2,
                t3: this.t3,
                twoPi: this.twoPi
            });
        } else {
            this.isSupport = false;
            this.message.error('当前图层不支持颜色处理');
            return;
        }
        this.raster.on('beforeoperations', (event) => {
            const controlIds = ['hue', 'chroma', 'lightness'];
            const data = event.data;
            controlIds.map(id => {
                data[id] = this[id];
            });
        });
    }

    triggerChange = () => {
        this.raster.changed();
    }

    cancel(options?: any): any {
        this.map.removeLayer(this.imageLayer);
    }

    /**
     * Convert an RGB pixel into an HCL pixel.
     * @param {Array<number>} pixel A pixel in RGB space.
     * @return {Array<number>} A pixel in HCL space.
     */
    rgb2hcl = (pixel: any) => {
        const red = this.rgb2xyz(pixel[0]);
        const green = this.rgb2xyz(pixel[1]);
        const blue = this.rgb2xyz(pixel[2]);

        const x = this.xyz2lab(
            (0.4124564 * red + 0.3575761 * green + 0.1804375 * blue) / this.Xn);
        const y = this.xyz2lab(
            (0.2126729 * red + 0.7151522 * green + 0.0721750 * blue) / this.Yn);
        const z = this.xyz2lab(
            (0.0193339 * red + 0.1191920 * green + 0.9503041 * blue) / this.Zn);

        const l = 116 * y - 16;
        const a = 500 * (x - y);
        const b = 200 * (y - z);

        const c = Math.sqrt(a * a + b * b);
        let h = Math.atan2(b, a);
        if (h < 0) {
            h += this.twoPi;
        }

        pixel[0] = h;
        pixel[1] = c;
        pixel[2] = l;

        return pixel;
    }
    /**
     * Convert an HCL pixel into an RGB pixel.
     * @param {Array<number>} pixel A pixel in HCL space.
     * @return {Array<number>} A pixel in RGB space.
     */
    hcl2rgb = (pixel: any) => {
        const h = pixel[0];
        const c = pixel[1];
        const l = pixel[2];

        const a = Math.cos(h) * c;
        const b = Math.sin(h) * c;

        let y = (l + 16) / 116;
        let x = isNaN(a) ? y : y + a / 500;
        let z = isNaN(b) ? y : y - b / 200;

        y = this.Yn * this.lab2xyz(y);
        x = this.Xn * this.lab2xyz(x);
        z = this.Zn * this.lab2xyz(z);

        pixel[0] = this.xyz2rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z);
        pixel[1] = this.xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z);
        pixel[2] = this.xyz2rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z);

        return pixel;
    }

    xyz2lab = (t) => {
        return t > this.t3 ? Math.pow(t, 1 / 3) : t / this.t2 + this.t0;
    }

    lab2xyz = (t) => {
        return t > this.t1 ? t * t * t : this.t2 * (t - this.t0);
    }

    rgb2xyz = (x) => {
        return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
    }

    xyz2rgb = (x) => {
        return 255 * (x <= 0.0031308 ?
            12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
    }
}
